package eo.descriptor.entity.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import eo.descriptor.entity.EntityDescriptor;
import eo.descriptor.property.PropertyDescriptor;

public class SimpleEntityDescriptor implements EntityDescriptor {
    private String entityName;

    private PropertyDescriptor idDescriptor;

    private Map<String, PropertyDescriptor> properties;

    private Set<EntityDescriptor> subclasses = new HashSet<EntityDescriptor>();

    private EntityDescriptor superClassDescriptor;

    private final Class<?> entityClass;

    public SimpleEntityDescriptor(String entityName, Class<?> entityClass) {
        this(entityName, entityClass, null, new ArrayList<PropertyDescriptor>());
    }

    public SimpleEntityDescriptor(final String entityName,
            Class<?> entityClass, final EntityDescriptor superClassDescriptor,
            final List<PropertyDescriptor> properties) {
        super();
        this.entityClass = entityClass;
        this.entityName = entityName;
        this.superClassDescriptor = superClassDescriptor;
        this.properties = new HashMap<String, PropertyDescriptor>();
        for (PropertyDescriptor propertyDescriptor : properties) {
            if (propertyDescriptor.isId()) {
                this.idDescriptor = propertyDescriptor;
            }
            this.properties.put(propertyDescriptor.getName(),
                    propertyDescriptor);
        }
    }

    public void addSubclass(final EntityDescriptor entity) {
        this.subclasses.add(entity);
    }

    /**
     * @return the entityName
     */
    public String getEntityName() {
        return this.entityName;
    }

    public Serializable getId(final Object entity) {
        return (Serializable) this.idDescriptor.getValue(entity);
    }

    /**
     * @return the idDescriptor
     */
    public PropertyDescriptor getIdDescriptor() {
        return this.idDescriptor;
    }

    /**
     * @return the properties
     */
    public Collection<? extends PropertyDescriptor> getProperties() {
        return this.properties.values();
    }

    public Collection<? extends EntityDescriptor> getSubclasses() {
        return new ArrayList<EntityDescriptor>(this.subclasses);
    }

    /**
     * @return the superClassDescriptor
     */
    public EntityDescriptor getSuperClassDescriptor() {
        return this.superClassDescriptor;
    }

    /**
     * @param entityName
     *            the entityName to set
     */
    public void setEntityName(final String entityName) {
        this.entityName = entityName;
    }

    /**
     * @param idDescriptor
     *            the idDescriptor to set
     */
    public void setIdDescriptor(final PropertyDescriptor idDescriptor) {
        this.idDescriptor = idDescriptor;
    }

    /**
     * @param properties
     *            the properties to set
     */
    public void setProperties(final List<PropertyDescriptor> properties) {
        this.properties = new HashMap<String, PropertyDescriptor>(properties
                .size());
        for (PropertyDescriptor pd : properties) {
            this.properties.put(pd.getName(), pd);
        }
    }

    /**
     * @param subclasses
     *            the subclasses to set
     */
    public void setSubclasses(final Set<EntityDescriptor> subclasses) {
        this.subclasses = subclasses;
    }

    /**
     * @param superClassDescriptor
     *            the superClassDescriptor to set
     */
    public void setSuperClassDescriptor(
            final EntityDescriptor superClassDescriptor) {
        this.superClassDescriptor = superClassDescriptor;
    }

    public Class<?> getEntityClass() {
        return this.entityClass;
    }

    public void addProperty(PropertyDescriptor desc) {
        this.properties.put(desc.getName(), desc);
    }

    @Override
    public String toString() {
        return "Descriptor for: " + this.getEntityName();
    }

    public Object createInstance() {
        try {
            return this.getEntityClass().newInstance();
        } catch (InstantiationException e) {
            throw new IllegalArgumentException("Failed to instantiate entity: "
                    + this.getEntityClass(), e);
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException("Failed to instantiate entity: "
                    + this.getEntityClass(), e);
        }
    }

    public PropertyDescriptor getProperty(String string) {
        return this.properties.get(string);
    }

}
